package com.tigerlee.stopmusic;

import java.io.IOException;
import java.lang.ref.WeakReference;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

public class StopMusicService extends Service implements OnPreparedListener {
	
	private MediaPlayer mPlayer = null;
	private AudioManager mAudioManager;
	
	private WakeLock mWakeLock;
	
	private static final int STOP_MUSIC = 1;
	private static final int START_ACTIVITY = 2;
	
	private String TAG = "StopMusicService";
	
	private OnAudioFocusChangeListener mAudioFocusChangeListener = new OnAudioFocusChangeListener() {

		@Override
		public void onAudioFocusChange(int focusChange) {
			switch (focusChange) {
			case AudioManager.AUDIOFOCUS_REQUEST_FAILED:
				Log.e(TAG, "AudioManager.AUDIOFOCUS_REQUEST_FAILED");
				break;
			case AudioManager.AUDIOFOCUS_GAIN:
				Log.e(TAG, "AudioManager.AUDIOFOCUS_GAIN");
				break;
			case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
				Log.e(TAG, "AudioManager.AUDIOFOCUS_GAIN_TRANSIENT");
				break;
			case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
				Log.e(TAG, "AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK");
				break;
			case AudioManager.AUDIOFOCUS_LOSS:
				// FIXME: We cannot stop music at this case..
				Log.e(TAG, "AudioManager.AUDIOFOCUS_LOSS");
				break;
			case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
				Log.e(TAG, "AudioManager.AUDIOFOCUS_LOSS_TRANSIENT");
				break;
			case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
				Log.e(TAG, "AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
				break;
			default:
				break;
			}
		}
	};
	
	static class MyHandler extends Handler{
		WeakReference<StopMusicService> mWeakReference;
		public MyHandler(StopMusicService service) {
			mWeakReference = new WeakReference<StopMusicService>(service);
		}
		@Override
		public void handleMessage(Message msg) {
			StopMusicService service = mWeakReference.get();
			switch (msg.what) {
			case STOP_MUSIC:
				// Defense code to set volume zero
				// service.volumnMute();
				
				// Stop playing silent sound
				service.stopMusic();
				break;
			case START_ACTIVITY:
				// Start new activity
				Intent i = new Intent(service.getApplicationContext(), StopMusicActivity.class);
				i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				service.startActivity(i);
				
				// service is no longer necessary. Will be started again if needed.
				service.stopSelf();
			default:
				break;
			}
			
		}
	};
	private MyHandler mHandler = new MyHandler(this); 
	
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		
		PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
		mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
		if(mWakeLock!=null) mWakeLock.acquire();
		
		// Get status of timer...
		MyPreference preference = new MyPreference(getApplicationContext());
		if(preference.isTurnOffMusic()){
			// 1. Send Media Button stop
			sendMediaButtonStop();

			// 2. Get audio focus
			mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
			/*
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN);
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_DTMF, AudioManager.AUDIOFOCUS_GAIN);
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_NOTIFICATION, AudioManager.AUDIOFOCUS_GAIN);
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN);
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_SYSTEM, AudioManager.AUDIOFOCUS_GAIN);
			mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN);
			*/
			// 3. prepare music player
			createMediaPlayerIfNeeded(getApplicationContext());
			mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			
			// 4. Play silent music... 
			configAndStartMediaPlayer();
			
			// 5. Set delay to stop music player 
			mHandler.sendEmptyMessageDelayed(STOP_MUSIC, 5000);
		}
		if(preference.isTurnOffWifi()){
			turnOffWifi();
		}
		if(preference.isTurnOffBluetooth()){
			turnOffBluetooth();
		}
		// Remove a notification and finish progress Activity with AsyncTask
		sendBroadcast(new Intent(UpdateNotificationReceiver.INTENT_ACTION_FINISH_TASK));

		// Let user know to stop music by showing a toast msg.
		String state = StopProgressActivity.changeTextStringByState(getApplicationContext());
		if (state == "") {
			state = getString(R.string.text_nothing);
			Toast.makeText(getApplicationContext(), getString(R.string.toast_nothing), Toast.LENGTH_LONG).show();
		} else {
			state = getString(R.string.text_stop) + " " + state + "!";
			Toast.makeText(getApplicationContext(), state, Toast.LENGTH_LONG).show();
		}
		// Initialize all preference..
		preference.initPreference();
		
		// Set delay to start main activity and stop this service...
		mHandler.sendEmptyMessageDelayed(START_ACTIVITY, 5500);
	}
	
	private void sendMediaButtonStop(){
		Log.e(TAG, "Broadcast MEDIA_BUTTON");
		long eventtime = SystemClock.uptimeMillis();
		Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
		KeyEvent downEvent = new KeyEvent(eventtime, eventtime,
				KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP, 0);
		downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent);
		sendOrderedBroadcast(downIntent, null);
		
		Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
		KeyEvent upEvent = new KeyEvent(eventtime, eventtime,
				KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP, 0);
		upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent);
		sendOrderedBroadcast(upIntent, null);
		
		sendOrderedBroadcast(downIntent, null);
		sendOrderedBroadcast(upIntent, null);
	}
	
	private void volumnMute(){
		mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 0, AudioManager.FLAG_PLAY_SOUND);
	}

	private void turnOffWifi() {
		// Actually request the wifi change and persistent
        // settings write off the UI thread, as it can take a
        // user-noticeable amount of time, especially if there's
        // disk contention.
        new AsyncTask<Void, Void, Void>() {
        	WifiManager mWifiManager = null;
        	protected void onPreExecute() {
        		mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        	};
            @Override
            protected Void doInBackground(Void... args) {
        		if (mWifiManager != null && mWifiManager.isWifiEnabled()) {
        			mWifiManager.setWifiEnabled(false);
        		}
                return null;
            }
        }.execute();
	}
	
	private void turnOffBluetooth() {
		new AsyncTask<Void, Void, Void>() {
			BluetoothAdapter mBluetoothAdapter = null;
			protected void onPreExecute() {
				mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
			};
            @Override
            protected Void doInBackground(Void... args) {
                if(mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()){
                	mBluetoothAdapter.disable();
                }
                return null;
            }
        }.execute();
        
	}
	private void turnOffGPS(){
		final ContentResolver resolver = getContentResolver();
        new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... args) {
                Settings.Secure.setLocationProviderEnabled(
                    resolver,
                    LocationManager.GPS_PROVIDER,
                    false);
                return true;
            }
        }.execute();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return super.onStartCommand(intent, flags, startId);
	}

	private void createMediaPlayerIfNeeded(Context context) {
		if (mPlayer == null) {
			mPlayer = new MediaPlayer();
			// Make sure the media player will acquire a wake-lock while
			// playing. If we don't do
			// that, the CPU might go to sleep while the song is playing,
			// causing playback to stop.
			//
			// Remember that to use this, we have to declare the
			// android.permission.WAKE_LOCK
			// permission in AndroidManifest.xml.
			mPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK);

			// we want the media player to notify us when it's ready preparing,
			// and when it's done
			// playing:
			mPlayer.setOnPreparedListener(this);
		} else {
			mPlayer.reset();
		}
	}

	/** Called when media player is done preparing. */
	@Override
	public void onPrepared(MediaPlayer mp) {
		// The media player is done preparing. That means we can start playing!
	}

	/**
	 * Reconfigures MediaPlayer according to audio focus settings and
	 * starts/restarts it. This method starts/restarts the MediaPlayer
	 * respecting the current audio focus state. So if we have focus, it will
	 * play normally; if we don't have focus, it will either leave the
	 * MediaPlayer paused or set it to a low volume, depending on what is
	 * allowed by the current focus settings. This method assumes mPlayer !=
	 * null, so if you are calling it, you have to do so from a context where
	 * you are sure this is the case.
	 */
	private void configAndStartMediaPlayer() {
		AssetFileDescriptor descriptor = null;
		try {
			descriptor = getAssets().openFd("silence.ogg");
			mPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
			descriptor.close();
			mPlayer.prepare();
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (mPlayer.isPlaying()){
			mPlayer.pause();
		}	
		else{
			mPlayer.start();
		}
			
	}
	
	private void stopMusic() {
		mPlayer.stop();
		// let go of all resources...
		relaxResources(true);
	}
	/**
	 * Releases resources used by the service for playback. This includes the
	 * "foreground service" status and notification, the wake locks and possibly
	 * the MediaPlayer.
	 * 
	 * @param releaseMediaPlayer
	 *            Indicates whether the Media Player should also be released or
	 *            not
	 */
	private void relaxResources(boolean releaseMediaPlayer) {
		// stop being a foreground service
		stopForeground(true);

		// stop and release the Media Player, if it's available
		if (releaseMediaPlayer && mPlayer != null) {
			mPlayer.reset();
			mPlayer.release();
			mPlayer = null;
		}
		if(mWakeLock!=null) mWakeLock.release();
	}

}
